/*====================================================================================
# Module of «ДЭНСИ: КАССА» complex is the front-office application for POS-systems based on fiscal registrators.
# © 2010, Kostuchenko Alexey (leo-dead@mail.ru).
# This is a FREE software, licensed under GNU/GPL terms. See details in LICENSING_ENG.TXT in main directory
#====================================================================================
# Модуль программного комплекса «ДЭНСИ: КАССА» - рабочее место кассира для POS-систем на базе фискальных регистраторов
# © 2010, Костюченко Алексей (leo-dead@mail.ru).
# Данная программа является свободным программным обеспечением, выпускается на условиях Стандартной Общественной Лицензии GNU/GPL
# Подробнее смотрите в файле LICENSING_RUS.TXT в основной директории
#====================================================================================*/

#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
#include "setup_cyberplat_pgsql.h"
#include "addon_func.h"

//==================================================================================//
SetupCyberplat::SetupCyberplat()
{
    puts("SetupCyberplat::SetupCyberplat()");
    Set_Db("Setup");
}

//==================================================================================//
SetupCyberplat::SetupCyberplat(const char * conf_path) : PGSQL(conf_path)
{
    printf("SetupCyberplat::SetupCyberplat(conf_path = %s)\n", conf_path);
}


//==================================================================================//
SetupCyberplat::SetupCyberplat(char *dbname, char *user, char *password, char *host, char *hostaddr, char *port, const char* log_path) : PGSQL(dbname, user, password, host, hostaddr, port, log_path)
{
    printf("SetupCyberplat::SetupCyberplat(dbname = <%s>, user = <%s>, password = <%s>, host = <%s>, hostaddr = <%s>, port = <%s>, log_path = <%s>)\n", dbname, user, password, host, hostaddr, port, log_path);
}

//==================================================================================//
SetupCyberplat::~SetupCyberplat()
{
    puts(" SetupCyberplat::~SetupCyberplat() ");
}

//==================================================================================//
#define CYBERPLAT_GET_ACTIVE_SCHEME "SELECT scheme_id, scheme_name FROM schemes WHERE scheme_id = (select scheme_id from activescheme)"
int SetupCyberplat::SelectActiveScheme()
{
    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_GET_ACTIVE_SCHEME) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_GET_ACTIVE_SCHEME);

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    if (PQntuples(result) != 1) {
        printf("Scheme_name not valid or scheme name was not found!!!\n");
        PQclear(result);
        return -4;
    }

    this->scheme_id = PQgetvalue(result, 0, 0);
    this->scheme_name = PQgetvalue(result, 0, 1);

    PQclear(result);
    return 0;
}

//==================================================================================//
#define CYBERPLAT_GET_SCHEME_ID "SELECT scheme_id FROM schemes WHERE scheme_name='%s'"
int SetupCyberplat::SetScheme(const char *scheme_name)
{
    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_GET_SCHEME_ID) + strlen(scheme_name)+1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_GET_SCHEME_ID, scheme_name);

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    if (PQntuples(result) != 1) {
        printf("Scheme_name not valid or scheme name was not found!!!\n");
        PQclear(result);
        return -4;
    }

    this->scheme_id = PQgetvalue(result, 0, 0);
    this->scheme_name = scheme_name;

    PQclear(result);
    return 0;
}

//==================================================================================//
#define CYBERPLAT_GET_BARCODES "SELECT cb.operator_id, cb.internal_id, cb.pattern, cb.replacement FROM cyberplat_barcode cb WHERE cb.scheme_id=%s"
int SetupCyberplat::GetBarcodes(TCyberplatBarcode *&codes, int &count)
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;
    
    query = (char *) calloc(strlen(CYBERPLAT_GET_BARCODES) + strlen(scheme_id.c_str()) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_GET_BARCODES, scheme_id.c_str());
    
    state = doSQL(myconnection, query);
    free(query);
    
    if (state != 2) return -1;
    
    count = PQntuples(result);

    if (count == 0) {
        PQclear(result);
        return 0;
    }

    codes = (TCyberplatBarcode *) calloc(count, sizeof(TCyberplatBarcode));
    if (codes == NULL) {
        PQclear(result);
        printf("NULL calloc for codes\n");
        return -1;
    }
    
    for (int i = 0; i < count; i++) {
        strcpy(codes[i].operator_id, PQgetvalue(result, i, 0));
        strcpy(codes[i].internal_id, PQgetvalue(result, i, 1));
        strcpy(codes[i].pattern, PQgetvalue(result, i, 2));
        strcpy(codes[i].replacement, PQgetvalue(result, i, 3));
    }

    PQclear(result);
    return 0;
}

//==================================================================================//
#define CYBERPLAT_DELETE_BARCODES "DELETE FROM cyberplat_barcode WHERE scheme_id=%s"
int SetupCyberplat::DeleteBarcodes()
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;
    
    query = (char *) calloc(strlen(CYBERPLAT_DELETE_BARCODES) + strlen(scheme_id.c_str()) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_DELETE_BARCODES, scheme_id.c_str());
    
    state = doSQL(myconnection, query);
    free(query);
    
    return state < 0 ? -1 : 0;
}

//==================================================================================//
#define CYBERPLAT_ADD_BARCODE "INSERT INTO cyberplat_barcode (scheme_id, operator_id, internal_id, pattern, replacement) VALUES (%s, %s, '%s', E'%s', E'%s')"
int SetupCyberplat::AddBarcode(TCyberplatBarcode code)
{
    if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_ADD_BARCODE) + strlen(scheme_id.c_str()) + strlen(code.operator_id) + strlen(code.internal_id) + 2*strlen(code.pattern) + 2*strlen(code.replacement) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    char *pattern = (char *) calloc(2*strlen(code.pattern), sizeof(char));
    char *replacement = (char *) calloc(2*strlen(code.replacement), sizeof(char));
    if ((pattern == NULL) || (replacement == NULL)) {
            printf("NULL calloc for patter/replacement\n");
            return -1;
        }

    int error;
    PQescapeStringConn(myconnection, pattern, code.pattern, strlen(code.pattern), &error);
    PQescapeStringConn(myconnection, replacement, code.replacement, strlen(code.replacement), &error);

    sprintf(query, CYBERPLAT_ADD_BARCODE, scheme_id.c_str(), code.operator_id, code.internal_id, pattern, replacement);
    free(pattern);
    free(replacement);

    state = doSQL(myconnection, query);
    free(query);

    return state < 0 ? -1 : 0;
}

//==================================================================================//
#define CYBERPLAT_GET_OPERATORS "SELECT operator_id, operator_name, checkurl, payurl, statusurl, account, fee FROM cyberplat_operators WHERE scheme_id=%s"
int SetupCyberplat::GetOperators(TCyberplatOperator *&operators, int &count)
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_GET_OPERATORS) + strlen(scheme_id.c_str()) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_GET_OPERATORS, scheme_id.c_str());

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    count = PQntuples(result);

    if (count == 0) {
        PQclear(result);
        return 0;
    }

    operators = (TCyberplatOperator *) calloc(count, sizeof(TCyberplatOperator));
    if (operators == NULL) {
        PQclear(result);
        printf("NULL calloc for operators\n");
        return -1;
    }

    for (int i = 0; i < count; i++) {
        strcpy(operators[i].operator_id, PQgetvalue(result, i, 0));
        strcpy(operators[i].operator_name, PQgetvalue(result, i, 1));
        strcpy(operators[i].checkurl, PQgetvalue(result, i, 2));
        strcpy(operators[i].payurl, PQgetvalue(result, i, 3));
        strcpy(operators[i].statusurl, PQgetvalue(result, i, 4));
        strcpy(operators[i].account, PQgetvalue(result, i, 5));
        strcpy(operators[i].fee, PQgetvalue(result, i, 6));
    }

    PQclear(result);
    return 0;
}

//==================================================================================//
#define CYBERPLAT_DELETE_OPERATORS "DELETE FROM cyberplat_operators WHERE scheme_id=%s"
int SetupCyberplat::DeleteOperators()
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_DELETE_OPERATORS) + strlen(scheme_id.c_str()) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_DELETE_OPERATORS, scheme_id.c_str());

    state = doSQL(myconnection, query);
    free(query);

    return state < 0 ? -1 : 0;
}

//==================================================================================//
#define CYBERPLAT_ADD_OPERATOR "INSERT INTO cyberplat_operators (scheme_id, operator_id, operator_name, checkurl, payurl, statusurl, account, fee) VALUES (%s, %s, E'%s', E'%s', E'%s', E'%s', E'%s', %s)"
int SetupCyberplat::AddOperator(TCyberplatOperator op)
{
    if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_ADD_OPERATOR) + strlen(scheme_id.c_str()) + strlen(op.operator_id) + strlen(op.operator_id) + 2*strlen(op.checkurl) + 2*strlen(op.payurl) + 2*strlen(op.statusurl) + 2*strlen(op.account) + strlen(op.fee) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    char *operator_name = (char *) calloc(2*strlen(op.operator_name), sizeof(char));
    char *checkurl = (char *) calloc(2*strlen(op.checkurl), sizeof(char));
    char *payurl = (char *) calloc(2*strlen(op.payurl), sizeof(char));
    char *statusurl = (char *) calloc(2*strlen(op.statusurl), sizeof(char));
    char *account = (char *) calloc(2*strlen(op.account), sizeof(char));
    if ((operator_name == NULL) || (checkurl == NULL) || (payurl == NULL) || (statusurl == NULL) || (account == NULL)) {
            printf("NULL calloc for patter/replacement\n");
            return -1;
        }

    int error;
    PQescapeStringConn(myconnection, operator_name, op.operator_name, strlen(op.operator_name), &error);
    PQescapeStringConn(myconnection, checkurl, op.checkurl, strlen(op.checkurl), &error);
    PQescapeStringConn(myconnection, payurl, op.payurl, strlen(op.payurl), &error);
    PQescapeStringConn(myconnection, statusurl, op.statusurl, strlen(op.statusurl), &error);
    PQescapeStringConn(myconnection, account, op.account, strlen(op.account), &error);

    sprintf(query, CYBERPLAT_ADD_OPERATOR, scheme_id.c_str(), op.operator_id, operator_name, checkurl, payurl, statusurl, account, op.fee);
    free(operator_name);
    free(checkurl);
    free(payurl);
    free(statusurl);
    free(account);

    state = doSQL(myconnection, query);
    free(query);

    return state < 0 ? -1 : 0;
}

//==================================================================================//
#define CYBERPLAT_GET_OPERATOR_BY_ID "SELECT operator_id, operator_name, checkurl, payurl, statusurl, account, fee FROM cyberplat_operators WHERE scheme_id=%s AND operator_id=%d"
int SetupCyberplat::GetOperatorById(int operator_id, TCyberplatOperator *&op)
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(CYBERPLAT_GET_OPERATOR_BY_ID) + strlen(scheme_id.c_str()) + 21, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, CYBERPLAT_GET_OPERATOR_BY_ID, scheme_id.c_str(), operator_id);

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    if (PQntuples(result) != 1) {
        PQclear(result);
        return -3;
    }

    op = (TCyberplatOperator *) calloc(1, sizeof(TCyberplatOperator));
    if (op == NULL) {
        PQclear(result);
        printf("NULL calloc for operators\n");
        return -1;
    }

	strcpy(op->operator_id, PQgetvalue(result, 0, 0));
	strcpy(op->operator_name, PQgetvalue(result, 0, 1));
	strcpy(op->checkurl, PQgetvalue(result, 0, 2));
	strcpy(op->payurl, PQgetvalue(result, 0, 3));
	strcpy(op->statusurl, PQgetvalue(result, 0, 4));
	strcpy(op->account, PQgetvalue(result, 0, 5));
	strcpy(op->fee, PQgetvalue(result, 0, 6));

    PQclear(result);
    return 0;
}

//==================================================================================//
const char *SetupCyberplat::GetProxy()
{
	char *value;
	GetParam("CyberplatProxy", value);
	proxy = value;
	free(value);
	return proxy.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetSSL()
{
	char *value;
	GetParam("CyberplatSSL", value);
	SSL = value;
	free(value);
	return SSL.c_str();
}

//==================================================================================//
int SetupCyberplat::GetTimeout()
{
	int value;
	GetParam("CyberplatTimeout", &value);
	return value;
}

//==================================================================================//
const char *SetupCyberplat::GetPointSD()
{
	char *value;
	GetParam("CyberplatPointSD", value);
	sd = value;
	free(value);
	return sd.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetPointAP()
{
	char *value;
	GetParam("CyberplatPointAP", value);
	ap = value;
	free(value);
	return ap.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetPointOP()
{
	char *value;
	GetParam("CyberplatPointOP", value);
	op = value;
	free(value);
	return op.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetPointKeys()
{
	char *value;
	GetParam("CyberplatPointKeys", value);
	keys = value;
	free(value);
	return keys.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetPointPass()
{
	char *value;
	GetParam("CyberplatPointPass", value);
	pass = value;
	free(value);
	return pass.c_str();
}

//==================================================================================//
const char *SetupCyberplat::GetBankKey()
{
	char *value;
	GetParam("CyberplatBankKey", value);
	bankkey = value;
	free(value);
	return bankkey.c_str();
}

//==================================================================================//
#define GET_PARAM "SELECT COALESCE(pv.value, p.default_value) FROM parameters p, parametersValues pv WHERE pv.param_id = p.param_id AND pv.scheme_id=%s AND p.param_name = '%s'"
int SetupCyberplat::GetParam(const char *param_name)
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(GET_PARAM) + strlen(scheme_id.c_str()) + strlen(param_name) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, GET_PARAM, scheme_id.c_str(), param_name);

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    if (PQntuples(result) != 1) {
    	PQclear(result);
    	return -3;
    }

    return 0;
}

//==================================================================================//
#define GET_STRING_PARAM "SELECT COALESCE(pv.value, p.default_value) FROM stringparameters p, stringparametersValues pv WHERE pv.stringparam_id = p.stringparam_id AND pv.scheme_id=%s AND p.stringparam_name = '%s'"
int SetupCyberplat::GetStringParam(const char *param_name)
{
	if (atoi(scheme_id.c_str()) < 0) {
        printf("Scheme is not defined! Use SetScheme!");
        return -1;
    }

    int state;
    char *query;

    query = (char *) calloc(strlen(GET_STRING_PARAM) + strlen(scheme_id.c_str()) + strlen(param_name) + 1, sizeof(char));
    if (query == NULL) {
        printf("NULL calloc for query\n");
        return -1;
    }

    sprintf(query, GET_STRING_PARAM, scheme_id.c_str(), param_name);

    state = doSQL(myconnection, query);
    free(query);

    if (state != 2) return -1;

    if (PQntuples(result) != 1) {
    	PQclear(result);
    	return -3;
    }

    return 0;
}

//==================================================================================//
int SetupCyberplat::GetParam(const char *param_name, bool *param_value)
{
    int state = GetParam(param_name);
    if (state != 0) return state;

    *(param_value) = strcmp(PQgetvalue(result, 0, 0), "0") != 0;

    PQclear(result);

    return 0;
}

//==================================================================================//
int SetupCyberplat::GetParam(const char *param_name, int *param_value)
{
    int state = GetParam(param_name);
    if (state != 0) return state;

    *(param_value) = atoi(PQgetvalue(result, 0, 0));

    PQclear(result);

    return 0;
}

//==================================================================================//
int SetupCyberplat::GetParam(const char *param_name, double *param_value)
{
    int state = GetParam(param_name);
    if (state != 0) return state;

    *(param_value) = atof(PQgetvalue(result, 0, 0));

    PQclear(result);

    return 0;
}

//==================================================================================//
int SetupCyberplat::GetParam(const char *param_name, char *&param_value)
{
    int state = GetStringParam(param_name);
    if (state != 0) return state;

    param_value = (char*) calloc(PQgetlength(result, 0, 0)+3, sizeof(char));
    assert(param_value != NULL);
    strcpy(param_value, PQgetvalue(result, 0, 0));

    PQclear(result);

    return 0;
}
